﻿using ClothingShopping.Core.Configuration;
using ClothingShopping.IRepository;
using ClothingShopping.IService;
using ClothingShopping.Repository;
using ClothingShopping.Service;
using FreeSql;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Bson;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using ClothingShopping.Util.AutoMapper;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Configuration;

namespace ClothingShopping.Core.Infrastructure
{
    /// <summary>
    /// 服务扩展
    /// </summary>
    public static class ServiceCollectionExtensions
    {
        /// <summary>
        /// 服务集扩展
        /// </summary>
        /// <param name="service"></param>
        /// <param name="dataConfig"></param>
        public static void ConfigureApplicationServices(this IServiceCollection service, DbConfig dbConfig, ShipmentConfig shipmentConfig)
        {
            AddFreeSql(service, dbConfig);
            service.AddScopeds();
            service.AddControllers(options =>
            {
                options.RespectBrowserAcceptHeader = false;//接受跨域
            }).AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.PropertyNameCaseInsensitive = false;// true:属性名称不区分大小写
                options.JsonSerializerOptions.WriteIndented=true;// 输出美化后的 JSON(缩进)
                options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(new TextEncoderSettings(UnicodeRanges.All)); // 支持 Unicode 字符编码
            });

            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            service.AddEndpointsApiExplorer();
            //if(shipmentConfig.IsDevelopment)
            {
                //开发环境
                service.AddSwaggerGen();
        }
        service.AddAuthentication(shipmentConfig.JwtConfig);
            service.AddAutoMapper(typeof(CustomAutoMapperProfile));
        }
        /// <summary>
        /// 注入程序集
        /// </summary>
        /// <param name="service"></param>
        public static void AddScopeds(this IServiceCollection service)
        {
            service.AddScoped<IUserRepository, UserRepository>();
            service.AddScoped<IUserService, UserService>();
        }
        /// <summary>
        /// JWT鉴权
        /// </summary>
        /// <param name="service"></param>
        public static void AddAuthentication(this IServiceCollection service,JwtConfig jwtConfig)
        {
            //defaultScheme默认方案为“Bearer”，可自定义方案如下
            //options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            //options.DefaultChallengeScheme = nameof(ResponseAuthenticationHandler); //401
            //options.DefaultForbidScheme = nameof(ResponseAuthenticationHandler);    //403
            service.AddAuthentication(options =>
            {
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.FromMinutes(jwtConfig.Expires),//TimeSpan.Zero,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = jwtConfig.Issuer,
                    ValidAudience = jwtConfig.Audience,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.SecurityKey))
                };
            });
        }

        /// <summary>
        /// 注入并配置Swagger服务
        /// </summary>
        /// <param name="service"></param>
        public static void AddSwaggerGen(this IServiceCollection service)
        {
            service.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo
                {
                    Version = "v1",
                    Title = "CS后台管理系统后端接口",
                    Description = "用于衣服商店便捷管理",
                    TermsOfService = new Uri("https://example.com/terms"),
                    Contact = new OpenApiContact
                    {
                        Name = "Example Contact",
                        Url = new Uri("https://example.com/contact")
                    },
                    License = new OpenApiLicense
                    {
                        Name = "Example License",
                        Url = new Uri("https://example.com/license")
                    }
                });
                // using System.Reflection;
                var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));

                //添加Jwt验证设置
                options.AddSecurityRequirement(new OpenApiSecurityRequirement()
                    {
                        {
                            new OpenApiSecurityScheme
                            {
                                Reference = new OpenApiReference
                                {
                                    Id = "Bearer",
                                    Type = ReferenceType.SecurityScheme
                                }
                            },
                            new List<string>()
                        }
                    });

                options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "Value: Bearer {token}",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey
                });
            });
        }

        /// <summary>
        /// 绑定和获取配置文件appsettings.josn的节点值
        /// </summary>
        /// <typeparam name="TConfig"></typeparam>
        /// <param name="section">配置节点集合</param>
        /// <param name="key">需要获取的节点</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static TConfig GetSection<TConfig>(this IConfiguration section,string key) where TConfig : class,new()
        {
            if (section == null)
                throw new ArgumentNullException(nameof(section));
            var tConfig = section.GetSection(key).Get<TConfig>();

            if (tConfig == null)
                throw new ArgumentNullException(nameof(tConfig));
            return tConfig;
        }


        /// <summary>
        /// 创建，绑定并将指定配置参数注册为服务
        /// </summary>
        /// <typeparam name="TConfig">配置参数</typeparam>
        /// <param name="services">服务描述符的集合</param>
        /// <param name="configuration">一组键/值应用程序配置属性</param>
        /// <returns>配置参数实例</returns>
        public static TConfig ConfigureStartupConfig<TConfig>(this IServiceCollection services, IConfiguration configuration) where TConfig : class, new()
        {
            if (services == null)
                throw new ArgumentNullException(nameof(services));

            if (configuration == null)
                throw new ArgumentNullException(nameof(configuration));

            //create instance of config
            var config = new TConfig();

            //bind it to the appropriate section of configuration
            configuration.Bind(config);

            //and register it as a service
            services.AddSingleton(config);

            return config;
        }

        public static void AddFreeSql(IServiceCollection service, DbConfig dataConfig)
        {
            if (dataConfig.CreateDb)
            {
                #region 创建数据库
                var db = new FreeSqlBuilder()
                       .UseConnectionString(dataConfig.Type, dataConfig.ConnectionString)
                       .Build();
                var sql = $"CREATE DATABASE '{dataConfig.CreateDatabaseName}' CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci'";
                switch (dataConfig.Type)
                {
                    case DataType.SqlServer:
                        sql = $"CREATE DATABASE [{dataConfig.CreateDatabaseName}]";
                        break;
                }
                db.Ado.ExecuteNonQuery(sql);
                #endregion
            }
            Func<IServiceProvider, IFreeSql> fsqlFactory = r =>
            {
                IFreeSql fsql = new FreeSql.FreeSqlBuilder()
                    .UseConnectionString(dataConfig.Type, dataConfig.ConnectionString)
                    .UseMonitorCommand(cmd => Console.WriteLine($"Sql：{cmd.CommandText}"))//监听SQL语句
                    .UseAutoSyncStructure(true) //自动同步实体结构到数据库，FreeSql不会扫描程序集，只有CRUD时才会生成表。
                    .Build();
                fsql.CodeFirst.IsAutoSyncStructure = dataConfig.IsAutoSyncDataStructure;//是否自动迁移实体
                return fsql;
            };
            service.AddSingleton<IFreeSql>(fsqlFactory);
        }
    }
}
